#region Copyright (c) 2006-2012 nHydrate.org, All Rights Reserved
//--------------------------------------------------------------------- *
//                          NHYDRATE.ORG                                *
//             Copyright (c) 2006-2012 All Rights reserved              *
//                                                                      *
//                                                                      *
//This file and its contents are protected by United States and         *
//International copyright laws.  Unauthorized reproduction and/or       *
//distribution of all or any portion of the code contained herein       *
//is strictly prohibited and will result in severe civil and criminal   *
//penalties.  Any violations of this copyright will be prosecuted       *
//to the fullest extent possible under law.                             *
//                                                                      *
//THE SOURCE CODE CONTAINED HEREIN AND IN RELATED FILES IS PROVIDED     *
//TO THE REGISTERED DEVELOPER FOR THE PURPOSES OF EDUCATION AND         *
//TROUBLESHOOTING. UNDER NO CIRCUMSTANCES MAY ANY PORTION OF THE SOURCE *
//CODE BE DISTRIBUTED, DISCLOSED OR OTHERWISE MADE AVAILABLE TO ANY     *
//THIRD PARTY WITHOUT THE EXPRESS WRITTEN CONSENT OF THE NHYDRATE GROUP *
//                                                                      *
//UNDER NO CIRCUMSTANCES MAY THE SOURCE CODE BE USED IN WHOLE OR IN     *
//PART, AS THE BASIS FOR CREATING A PRODUCT THAT PROVIDES THE SAME, OR  *
//SUBSTANTIALLY THE SAME, FUNCTIONALITY AS THIS PRODUCT                 *
//                                                                      *
//THE REGISTERED DEVELOPER ACKNOWLEDGES THAT THIS SOURCE CODE           *
//CONTAINS VALUABLE AND PROPRIETARY TRADE SECRETS OF NHYDRATE,          *
//THE REGISTERED DEVELOPER AGREES TO EXPEND EVERY EFFORT TO             *
//INSURE ITS CONFIDENTIALITY.                                           *
//                                                                      *
//THE END USER LICENSE AGREEMENT (EULA) ACCOMPANYING THE PRODUCT        *
//PERMITS THE REGISTERED DEVELOPER TO REDISTRIBUTE THE PRODUCT IN       *
//EXECUTABLE FORM ONLY IN SUPPORT OF APPLICATIONS WRITTEN USING         *
//THE PRODUCT.  IT DOES NOT PROVIDE ANY RIGHTS REGARDING THE            *
//SOURCE CODE CONTAINED HEREIN.                                         *
//                                                                      *
//THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE.              *
//--------------------------------------------------------------------- *
#endregion

using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Xml;
using nHydrate.Generator.Common.GeneratorFramework;
using nHydrate.Generator.Common.Util;

namespace nHydrate.Generator.Models
{
	//[Editor(typeof(nHydrate.Generator.Design.Editors.ReferenceCollectionEditor), typeof(System.Drawing.Design.UITypeEditor))]
	public class ReferenceCollection : BaseModelCollection, IEnumerable<Reference>
	{
		#region Member Variables

		protected List<Reference> _references = null;
		protected string _objectSingular = "Reference";
		protected string _objectPlural = "References";
		protected int _imageIndex = -1;
		protected int _selectedImageIndex = -1;
		protected INHydrateModelObject _parent = null;
		protected ReferenceType _refType = ReferenceType.Table;

		#endregion

		#region Constructor

		public ReferenceCollection(INHydrateModelObject root)
			: base(root)
		{
			_references = new List<Reference>();
		}

		public ReferenceCollection(INHydrateModelObject root, INHydrateModelObject parent, ReferenceType refType)
			: this(root)
		{
			_parent = parent;
			_refType = refType;
		}

		#endregion

		#region Property Implementations

		[Browsable(false)]
		public INHydrateModelObject Parent
		{
			get { return _parent; }
		}

		[Browsable(false)]
		public ReferenceType RefType
		{
			get { return _refType; }
		}

		[Browsable(false)]
		public string ObjectSingular
		{
			get { return _objectSingular; }
			set { _objectSingular = value; }
		}

		[Browsable(false)]
		public string ObjectPlural
		{
			get { return _objectPlural; }
			set { _objectPlural = value; }
		}

		[Browsable(false)]
		public int ImageIndex
		{
			get { return _imageIndex; }
			set { _imageIndex = value; }
		}

		[Browsable(false)]
		public int SelectedImageIndex
		{
			get { return _selectedImageIndex; }
			set { _selectedImageIndex = value; }
		}

		#endregion

		#region Methods

		public Reference[] GetById(int id)
		{
			var retval = new ArrayList();
			foreach(Reference element in this)
			{
				if (element.Ref == id)
					retval.Add(element);
			}
			return (Reference[])retval.ToArray(typeof(Reference));
		}

		private Random _rnd = new Random();
		internal int NextIndex()
		{
			var retval = _rnd.Next(1, int.MaxValue);
			while (this.ToList<Reference>().Count(x => x.Ref == retval) != 0)
			{
				retval = _rnd.Next(1, int.MaxValue);
			}
			return retval;
		}

		public Reference GetByKey(string key)
		{
			foreach (Reference element in this)
			{
				if (StringHelper.Match(element.Key, key, true))
					return element;
			}
			return null;
		}

		public Array FindReferencedObject(string key)
		{
			var retval = new ArrayList();
			foreach (INHydrateModelObject element in this)
			{
				if (StringHelper.Match(((Reference)element).Object.Key, key, true))
					retval.Add(element);
			}
			return retval.ToArray();
		}

		#endregion

		#region IXMLable Members

		public override void XmlAppend(XmlNode node)
		{
			try
			{
				var oDoc = node.OwnerDocument;

				XmlHelper.AddAttribute(node, "key", this.Key);

				foreach(var Reference in _references)
				{
					var ReferenceNode = oDoc.CreateElement("f");
					Reference.XmlAppend(ReferenceNode);
					node.AppendChild(ReferenceNode);
				}
			}
			catch(Exception ex)
			{
				throw;
			}

		}

		public override void XmlLoad(XmlNode node)
		{
			try
			{
				_key = XmlHelper.GetAttributeValue(node, "key", string.Empty);
				var referenceNodes = node.SelectNodes("Reference"); //deprecated, use "f"
				if (referenceNodes.Count == 0) referenceNodes = node.SelectNodes("f");
				foreach(XmlNode referenceNode in referenceNodes)
				{
					var newReference = new Reference(this.Root);
					newReference.XmlLoad(referenceNode);
					_references.Add(newReference);
				}

				this.Dirty = false;
			}
			catch(Exception ex)
			{
				throw;
			}
		}

		#endregion

		#region IList Members

		//[Browsable(false)]
		//public bool IsReadOnly
		//{
		//  get { return _references.IsReadOnly; }
		//}

		public Reference this[int index]
		{
			get { return _references[index]; }
			//set { _references[index] = value; }
		}

		public Reference this[string name]
		{
			get
			{
				var retval = FindByName(name);
				if (retval == null)
					throw new Exception("Item not found!");
				else
					return retval;
			}
		}

		public Reference FindByName(string name)
		{
			foreach (Reference element in this)
			{
				switch (element.RefType)
				{
					case ReferenceType.Column:
						if (((Column)element.Object).Name == name)
							return element;
						break;
					case ReferenceType.Relation:
						if (((Relation)element.Object).ConstraintName == name)
							return element;
						break;
					case ReferenceType.Table:
						if (((Table)element.Object).Name == name)
							return element;
						break;
					case ReferenceType.CustomView:
						if (((CustomView)element.Object).Name == name)
							return element;
						break;
					case ReferenceType.CustomRetrieveRule:
						if (((CustomRetrieveRule)element.Object).Name == name)
							return element;
						break;
					case ReferenceType.Parameter:
						if (((Parameter)element.Object).Name == name)
							return element;
						break;
					case ReferenceType.CustomViewColumn:
						if (((CustomViewColumn)element.Object).Name == name)
							return element;
						break;
					case ReferenceType.FunctionColumn:
						if (((FunctionColumn)element.Object).Name == name)
							return element;
						break;
				}
			}
			return null;
		}

		public void RemoveAt(int index)
		{
			_references.RemoveAt(index);
		}

		public void Insert(int index, Reference value)
		{
			_references.Insert(index, value);
		}

		public void Remove(Reference value)
		{
			_references.Remove(value);
		}

		public void RemoveRange(IEnumerable range)
		{
			foreach(Reference element in range)
				this.Remove(element);
		}

		public bool Contains(Reference value)
		{
			return _references.Contains(value);
		}

		public bool Contains(int id)
		{
			foreach(Reference reference in this)
			{
				if (reference.Ref == id)
					return true;
			}
			return false;
		}

		public bool Contains(string key)
		{
			foreach (Reference reference in this)
			{
				if (reference.Key == key)
					return true;
				if (reference.Object.Key == key)
					return true;
			}
			return false;
		}

		public override void Clear()
		{
			//Clear each one-by-one
			for (var ii = this.Count - 1; ii >= 0; ii--)
			{
				this.RemoveAt(0);
			}
		}

		public int IndexOf(Reference value)
		{
			return _references.IndexOf(value);
		}

		public void Add(Reference value)
		{
			_references.Add(value);
		}

		public override void AddRange(ICollection list)
		{
			foreach (Reference reference in list)
			{
				_references.Add(reference);
			}
		}

		public Reference Add()
		{
			var newItem = new Reference(this.Root);
			newItem.Ref = NextIndex();
			this.Add(newItem);
			return newItem;
		}

		//[Browsable(false)]
		//public bool IsFixedSize
		//{
		//  get { return _references.IsFixedSize; }
		//}

		#endregion

		#region ICollection Members

		[Browsable(false)]
		public override bool IsSynchronized
		{
			get { return false; }
		}

		[Browsable(false)]
		public override int Count
		{
			get
			{
				return _references.Count;
			}
		}

		public override void CopyTo(Array array, int index)
		{
			_references.CopyTo((Reference[])array, index);
		}

		private readonly object _syncRoot = "QQQ";

		[Browsable(false)]
		public override object SyncRoot
		{
			get { return _syncRoot; }
		}

		#endregion

		#region IEnumerable Members

		public override IEnumerator GetEnumerator()
		{
			return _references.GetEnumerator();
		}

		#endregion


		#region IEnumerable<Reference> Members


		#endregion

		#region IEnumerable<Reference> Members

		IEnumerator<Reference> IEnumerable<Reference>.GetEnumerator()
		{
			return _references.GetEnumerator();
		}

		#endregion

		#region IEnumerable Members

		IEnumerator IEnumerable.GetEnumerator()
		{
			return _references.GetEnumerator();
		}

		#endregion
	}
}
